#pragma once

#include <nxos.h>

#include "surface.h"
#include "event.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define NX_WINDOW_IPC_NAME "@WindowManager"
#define NX_WINDOW_HELPER_STACK_SZIE 0x4000

#define NX_WINDOW_FLAG_DIRECTDRAW   0x01
#define NX_WINDOW_FLAG_FULLSCREEN   0x02
#define NX_WINDOW_FLAG_FULLSCREEN_DESKTOP   (NX_WINDOW_FLAG_FULLSCREEN | 0x1000)
#define NX_WINDOW_FLAG_FULLSCREEN_DIRECTDRAW  (NX_WINDOW_FLAG_DIRECTDRAW | NX_WINDOW_FLAG_FULLSCREEN)

typedef int NX_WindowID;

typedef struct NX_WindowConfig
{
    int x, y, width, height;
    NX_U32 event_mask;
} NX_WindowConfig;

typedef struct NX_VideoInfo
{
    int width, height;
    NX_Addr phyBaseAddr;
} NX_VideoInfo;

typedef struct NX_WindowConnect
{
    NX_Solt vmo;
    NX_Solt event;
    NX_Surface surface[1];
    NX_Solt vmo_map;
} NX_WindowConnect;

typedef struct NX_Window
{
    NX_List list;
    NX_WindowConnect connect;
    NX_Surface oldSurface;
    NX_U32 flags;
    NX_WindowID id;
} NX_Window;

typedef enum NX_RequestID
{
    NX_WINDOW_CREATE,
    NX_WINDOW_DESTORY,
    NX_WINDOW_CONFIG_GET,
    NX_WINDOW_EVENT_MASK_SET,
    NX_WINDOW_SHOW,
    NX_WINDOW_HIDE,
    NX_WINDOW_UPDATE,
    NX_WINDOW_MOVE,
    NX_WINDOW_RESIZE,
    NX_VIDEO_GET_INFO,
} NX_RequestID;

typedef struct NX_Request
{
    NX_RequestID req;

    union
    {
        struct NX_WINDOW_CREATE
        {
            int x;
            int y;
            int width;
            int height;
            NX_Color bg;
            NX_U32 flags;
            NX_WindowConnect connect;
        } NX_WINDOW_CREATE;
        struct NX_WINDOW_DESTORY
        {
            NX_WindowID id;
        } NX_WINDOW_DESTORY;
        struct NX_WINDOW_CONFIG_GET
        {
            NX_WindowID id;
            NX_WindowConfig config;
        } NX_WINDOW_CONFIG_GET;
        struct NX_WINDOW_EVENT_MASK_SET
        {
            NX_WindowID id;
            NX_U32 event_mask;
        } NX_WINDOW_EVENT_MASK_SET;
        struct NX_WINDOW_SHOW
        {
            NX_WindowID id;
        } NX_WINDOW_SHOW;
        struct NX_WINDOW_HIDE
        {
            NX_WindowID id;
        } NX_WINDOW_HIDE;
        struct NX_WINDOW_UPDATE
        {
            NX_WindowID id;
        } NX_WINDOW_UPDATE;
        struct NX_WINDOW_MOVE
        {
            NX_WindowID id;
            int dx;
            int dy;
        } NX_WINDOW_MOVE;
        struct NX_WINDOW_RESIZE
        {
            NX_WindowID id;
            int width;
            int height;
            NX_WindowConnect connect;
        } NX_WINDOW_RESIZE;
        struct NX_VIDEO_GET_INFO
        {
            NX_VideoInfo info;
        } NX_VIDEO_GET_INFO;
    };
} NX_Request;

typedef void (*NX_WindowQuitEventType)(void);

#define NX_WINDOW_GET_REQUEST_SIZE(tag) (NX_OFFSET_OF_STRUCT(NX_Request, tag) + sizeof(struct tag))
#define NX_WINDOW_GET_REQUEST(name, tag, ptr) struct tag *name = (&(((NX_Request *)(ptr))->tag))

NX_Error NX_WindowPollEvent(NX_Window *win, NX_WindowEvent *e);
NX_Error NX_WindowWaitEvent(NX_Window *win, NX_WindowEvent *e);

NX_Window * NX_WindowCreate(int x, int y, int width, int height, NX_Color bg, NX_U32 flags);
NX_Error  NX_WindowDestroy(NX_Window *win);
NX_Error  NX_WindowSetEventMask(NX_Window *win, NX_U32 event_mask);
NX_Error  NX_WindowGetConfig(NX_Window *win, NX_WindowConfig *config);
NX_Error  NX_WindowShow(NX_Window *win);
NX_Error  NX_WindowHide(NX_Window *win);
NX_Error  NX_WindowUpdate(NX_Window *win);
NX_Error  NX_WindowMove(NX_Window *win, int dx, int dy);
NX_Error NX_WindowResize(NX_Window *win, int width, int height);
NX_Error NX_WindowControlGroup(NX_RequestID req);
void NX_WindowSetQuit(NX_WindowQuitEventType handler);

NX_Surface * NX_WindowGetSurface(NX_Window *win);
NX_VideoInfo * NX_VideoGetInfo(void);

NX_Error NX_WindowInit(void);
NX_Error NX_WindowExit(void);

#ifdef __cplusplus
}
#endif